package puzzle;

import java.util.*;

public class Tray {
	/**
	 * height of the Tray
	 */
	private int height;
	/**
	 * width of the tray
	 */
	private int width;
	/**
	 * List of all the pieces on the tray
	 */
	private ArrayList<Block> blocks;
	
	public ArrayList<Block> goal;
	/**
	 * Tray occupation matrix
	 * true if the box is occupied false if it is not.
	 */
	private boolean[][] occupied;

	/**
	 * creates a tray
	 */
	public Tray(){
		blocks = new ArrayList<Block>();
		goal = new ArrayList<Block>();
	}

	
	public Tray clone(){
		Tray t = new Tray();
		t.height=height;
		t.width=width;
		for(Block b : blocks){
			t.blocks.add(b.clone());
		}
		t.occupied = new boolean[height][width];	
		for(Block b : t.blocks){
			t.putBlock(b, b.getPosx(), b.getPosy());
		}
		t.goal=goal;
		return t;
	}
	/**
	 * initialises the tray from the input file 
	 * defines the tray's height and width
	 * @param TrayList integer list containing the desired height and width
	 */
	public void InitTrayList(ArrayList<Integer> TrayList) {
		height = TrayList.get(0);
		width = TrayList.get(1);
		occupied = new boolean[height][width];	
		for(int i=0;i<height;i++){
			for(int j=0;j<width;j++){
				occupied[i][j]=false;
			}
		}
	}
	
	
	/**
	 * gets the tray's height
	 * @return the tray's height
	 */
	public int getT_heigth() {
		return height;
	}

	/**
	 * gets the tray's width
	 * @return the tray's width
	 */
	public int getT_width() {
		return width;
	}

	/**
	 * gets the tray's pieces list
	 * @return the tray's pieces list
	 */
	public ArrayList<Block> getBlock() {
		return blocks;
	}

	/**
	 * gets the tray's occupation matrix
	 * @return the tray's occupation matrix
	 */
	public boolean[][] getOccupied() {
		return occupied;
	}

	public boolean moveOK(Block myPiece,int newX,int newY){
		if(newX+myPiece.getHeight()>height||newY+myPiece.getWidth()>width||newX<0||newY<0){
			
			return false;
		}
		for(int k = 0;k<myPiece.getHeight();k++){
			for(int l = 0;l<myPiece.getWidth();l++){
				if(occupied[newX+k][newY+l]){
					return false;
				}
					
			}
		}
		return true;
	}

	/**
	 * function that removes a piece from the occupation matrix
	 * this function is private because it can only be called to move the piece
	 * @param myPiece the piece to remove
	 */
	private void removeBlock(Block myPiece){

		for(int k = 0;k<myPiece.getHeight();k++){
			for(int l = 0;l<myPiece.getWidth();l++){
				occupied[myPiece.getPosx()+k][myPiece.getPosy()+l]=false;
			}
		}
	}

	/**
	 * function that puts a piece on the occupation matrix
	 * @param myPiece the piece to put
	 * @throws IllegalStateException when the position is not valid
	 */
	public void putBlock(Block myPiece,int newX,int newY){
		myPiece.setPosx(newX);
		myPiece.setPosy(newY);
			for(int k = 0;k<myPiece.getHeight();k++){
				for(int l = 0;l<myPiece.getWidth();l++){
					occupied[myPiece.getPosx()+k][myPiece.getPosy()+l]=true;
				}
			}
	}

	public boolean moveBlock(Block myBlock, int posx, int posy){
		removeBlock(myBlock);
		if(moveOK(myBlock,posx,posy))	{
			putBlock(myBlock,posx,posy);
			return true;
		}
		else {
			putBlock(myBlock,myBlock.getPosx(),myBlock.getPosy());
			return false;
		}
		
	}


	public boolean moveDirection(Block myblock, int direction){
		switch(direction){
		case 1: return moveBlock(myblock,myblock.getPosx()-1, myblock.getPosy());
		case 4: return moveBlock(myblock,myblock.getPosx(), myblock.getPosy()+1);
		case 3: return moveBlock(myblock,myblock.getPosx(), myblock.getPosy()-1);
		case 2: return moveBlock(myblock,myblock.getPosx()+1, myblock.getPosy());
		}
		return false;
	}
	/**
	 * function that prints the occupation matrix
	 */
	public void printOccupied(){
		for(int i = 0; i<height;i++){
			System.out.println("");
			for(int j = 0; j<width;j++){
				System.out.print(occupied[i][j]+ " | ");
			}
		}
		System.out.println("");
	}
	
	public boolean win(){
		int nb = 0;
		for(Block g: goal){
			for(Block b : blocks){
				if(b.equals(g)){
					nb++;
					break;		
				}
			}
		}
		return (nb==goal.size());
	}

	public void printBlocks(){
		for(Block b : blocks){
			System.out.println(b);
		}
	}
	
	public Block searchBlock(int posX, int posY){
		for(Block b : blocks){
			if(b.getPosx()==posX && b.getPosy()==posY)
				return b;
		}
		return null;
	}
}
